package com.espirit.log;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Stream;

public class Scanner {

	private String path;
	
	private String output;
	
	private FileSystem fs;
	
	private Map<String,Queue<Long>> result;
	
	private volatile int maxHint;
	
	private boolean succ;
	
	public Scanner(String path,String output){
		fs = FileSystems.getDefault();
		result = new ConcurrentHashMap<String, Queue<Long>>();
		succ = true;
		this.path= path;
		this.output = output;
	}
	
	public void scan(final String regex){
		Path root = fs.getPath(path);
		try {
			@SuppressWarnings("resource")
			Stream<Path> paths = Files.walk(root);
			List<Future<Boolean>> results = new LinkedList<Future<Boolean>>();
			ExecutorService es = Executors.newCachedThreadPool();
			paths.parallel().forEach(path -> {
				if (Files.isRegularFile(path)) {
					ScanTask task = new ScanTask(path, regex);
					results.add(es.submit(task));
				}
			});
			results.forEach(ret -> {
				try {
					Boolean b = ret.get();
					succ = succ && b;
					System.out.println("finish!~~" + b);
				} catch (Exception e) {
					e.printStackTrace();
				}
			});
			if (succ) {
				File file = fs.getPath(output).toFile();
				try(FileWriter writer = new FileWriter(file);
						BufferedWriter bw = new BufferedWriter(writer)){
					
					for (Entry<String, Queue<Long>> entry : result.entrySet()) {
						bw.write(entry.getKey()+"\t");
						for (Long value : entry.getValue()) {
							bw.write(String.valueOf(value)+"\t");
						}
						bw.newLine();
					}
				}catch (Exception ex) {
					ex.printStackTrace();
				}
			}
			es.shutdown();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
	class ScanTask implements Callable<Boolean>{
		private Path path;
		private String regex;
		
		public ScanTask(Path path,String regex){
			this.path = path;
			this.regex = regex;
		}

		@Override
		public Boolean call(){
			try(FileReader fr = new FileReader(path.toFile());
					BufferedReader br = new BufferedReader(fr)){
				String line;
				while ( (line = br.readLine())!=null) {
					processLine(line);
				}
			}catch (Exception e) {
				e.printStackTrace();
				return Boolean.FALSE;
			}
			return Boolean.TRUE;
		}

		private void processLine(String line) {
			if(line.matches(regex)){
				line = line.replace(' ', '\t');
				while(line.contains("\t\t")){
					line = line.replace("\t\t", "\t");
				}
				String[] parts =line.split("\t");
				int length = parts.length;
				if (length>3) {
					String fileName = parts[length-3];
					Queue<Long> queue = result.getOrDefault(fileName, new ConcurrentLinkedQueue<Long>());
					queue.add(Long.parseLong(parts[length-1]));
					if (maxHint < queue.size()) {
						maxHint = queue.size();
					}
					result.put(fileName, queue);
				}
			}
		}
	}
}
